#include "eqctrldelegate.h"
#include "qvaluespinbox.h"
#include "dm/filter.h"

#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QComboBox>
#include <QCheckBox>
#include <QDebug>

BaseDelegate::BaseDelegate(QObject *parent)
    : QItemDelegate{parent}
{

}

void BaseDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(index);
    editor->setGeometry(option.rect);
}

SpinBoxDelegate::SpinBoxDelegate(const int &min, const int &max, QObject *parent)
    : BaseDelegate{parent}
    , m_min{min}
    , m_max{max}
{

}

QWidget *SpinBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(option);
    Q_UNUSED(index);

    m_index = index;
    auto editor = new QSpinBox(parent);
    editor->setMinimum(m_min);
    editor->setMaximum(m_max);
    connect(editor, QOverload<int>::of(&QSpinBox::valueChanged), this, &SpinBoxDelegate::onValueChanged);

    return editor;
}

void SpinBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    m_index = index;
    auto value = index.model()->data(index, Qt::DisplayRole).toInt();
    auto spinBox = qobject_cast<QSpinBox*>(editor);
    spinBox->setValue(value);
    emit startEdit(index);
}

void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    auto spinBox = qobject_cast<QSpinBox*>(editor);
    spinBox->interpretText();
    auto value = spinBox->value();
    model->setData(index, value, Qt::EditRole);
}

void SpinBoxDelegate::onValueChanged(int value)
{
    if (m_index.isValid()) {
        QAbstractItemModel *model = const_cast<QAbstractItemModel*>(m_index.model());
        if (model) {
            model->setData(m_index, value, Qt::EditRole);
        }
    }
}

DoubleSpinBoxDelegate::DoubleSpinBoxDelegate(const double &min, const double &max, const double &step, const int &decimal, QObject *parent)
    : BaseDelegate{parent}
    , m_min{min}
    , m_max{max}
    , m_step{step}
    , m_decimal{decimal}
{

}

QWidget *DoubleSpinBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(option);
    Q_UNUSED(index);

    m_index = index;
    auto editor = new QDoubleSpinBox(parent);
    editor->setMinimum(m_min);
    editor->setMaximum(m_max);
    editor->setSingleStep(m_step);
    editor->setDecimals(m_decimal);

    connect(editor, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &DoubleSpinBoxDelegate::onValueChanged);

    return editor;
}

void DoubleSpinBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    m_index = index;
    auto value = index.model()->data(index, Qt::DisplayRole).toDouble();
    auto spinBox = qobject_cast<QDoubleSpinBox*>(editor);
    spinBox->setValue(value);
    emit startEdit(index);
}

void DoubleSpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    auto spinBox = qobject_cast<QDoubleSpinBox*>(editor);
    spinBox->interpretText();
    auto value = spinBox->value();
    model->setData(index, value, Qt::EditRole);
}

void DoubleSpinBoxDelegate::onValueChanged(double value)
{
    if (m_index.isValid()) {
        QAbstractItemModel *model = const_cast<QAbstractItemModel*>(m_index.model());
        if (model) {
            model->setData(m_index, qRound(value / m_step) * m_step, Qt::EditRole);
        }
    }
}

QValueSpinBoxDelegate::QValueSpinBoxDelegate(QObject *parent)
    : BaseDelegate{parent}
{

}

QWidget *QValueSpinBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(option);
    Q_UNUSED(index);

    m_index = index;
    auto editor = new QValueSpinBox(parent);

    connect(editor, QOverload<int>::of(&QValueSpinBox::valueChanged), this, &QValueSpinBoxDelegate::onValueChanged);

    return editor;
}

void QValueSpinBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    m_index = index;
    auto value = index.model()->data(index, Qt::DisplayRole).toDouble();
    auto spinBox = qobject_cast<QValueSpinBox*>(editor);
    spinBox->setValue(Filter::qToBw(value));
    emit startEdit(index);
}

void QValueSpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    auto spinBox = qobject_cast<QValueSpinBox*>(editor);
    spinBox->interpretText();
    auto value = spinBox->value();
    model->setData(index, Filter::bwToQ(value), Qt::EditRole);
}

void QValueSpinBoxDelegate::onValueChanged(int value)
{
    if (m_index.isValid()) {
        QAbstractItemModel *model = const_cast<QAbstractItemModel*>(m_index.model());
        if (model) {
            model->setData(m_index, Filter::bwToQ(value), Qt::EditRole);
        }
    }
}

ComboBoxDelegate::ComboBoxDelegate(QObject *parent)
    : BaseDelegate{parent}
{
    for (auto it = EQ_TYPE.begin(); it != EQ_TYPE.end(); ++it) {
        m_list.append(tr(*it));
    }
}

QWidget *ComboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(option);
    Q_UNUSED(index);

    m_index = index;
    auto editor = new QComboBox(parent);
    editor->addItems(m_list);

    connect(editor, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ComboBoxDelegate::onValueChanged);

    return editor;
}

void ComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    m_index = index;
    auto value = index.model()->data(index, Qt::DisplayRole).toString();
    auto comboBox = static_cast<QComboBox*>(editor);
    comboBox->setCurrentText(value);
    emit startEdit(index);
}

void ComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    auto comboBox = static_cast<QComboBox*>(editor);
    model->setData(index, comboBox->currentIndex(), Qt::EditRole);
}


void ComboBoxDelegate::onValueChanged(int value)
{
    if (m_index.isValid()) {
        QAbstractItemModel *model = const_cast<QAbstractItemModel*>(m_index.model());
        if (model) {
            model->setData(m_index, value, Qt::EditRole);
        }
    }
}



CheckBoxDelegate::CheckBoxDelegate(QObject *parent)
    : BaseDelegate{parent}
{

}

QWidget *CheckBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(option);
    Q_UNUSED(index);

    m_index = index;
    auto editor = new QCheckBox(parent);

    connect(editor, &QCheckBox::stateChanged, this, &CheckBoxDelegate::onValueChanged);

    return editor;
}

void CheckBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    m_index = index;
    auto value = index.model()->data(index, Qt::DisplayRole).toBool();
    auto checkBox = qobject_cast<QCheckBox*>(editor);
    checkBox->setChecked(value);
    emit startEdit(index);
}

void CheckBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    auto checkBox = qobject_cast<QCheckBox*>(editor);

    auto value = checkBox->isChecked();
    model->setData(index, value, Qt::EditRole);
}

void CheckBoxDelegate::onValueChanged(int value)
{
    if (m_index.isValid()) {
        QAbstractItemModel *model = const_cast<QAbstractItemModel*>(m_index.model());
        if (model) {
            model->setData(m_index, value, Qt::EditRole);
        }
    }
}
